using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Collections.ObjectModel;

namespace VisualTreeInspector
{
    /// <summary>
    /// Represents an entry in the Silverlight visual
    /// tree.
    /// </summary>
    public class VisualStructure
    {
        /// <summary>
        /// Gets the total visual children of this
        /// element, not including itself. Includes
        /// children of children.
        /// </summary>
        public int TotalChildren
        {
            get 
            {
                int toReturn = 0;

                foreach (var item in Children)
                {
                    toReturn += 1;
                    toReturn += item.TotalChildren;
                }

                return toReturn;
            
            }
        }

        /// <summary>
        /// Gets the immediate visual children of
        /// this element, not including children of
        /// children.
        /// </summary>
        public int LocalChildren
        {
            get { return this.Children.Count; }
        }


        /// <summary>
        /// Stores the total number of items in
        /// this ItemsControl.
        /// </summary>
        private int _TotalItems;
        
        /// <summary>
        /// Gets the total number of items of the
        /// ItemsControl represented by this VisualStructure.
        /// </summary>
        public int TotalItems
        {
            get { return _TotalItems; }
        }

        /// <summary>
        /// Stores the hashcode of this item.
        /// </summary>
        private int _HashCode;

        /// <summary>
        /// Gets the hashcode of this item in
        /// the visual tree.
        /// </summary>
        public int HashCode
        {
            get { return _HashCode; }
        }

        /// <summary>
        /// Gets the name of the object via the FrameworkElement.NameProperty
        /// dependency property.
        /// </summary>
        /// <param name="elem">The element to get the name of.</param>
        private void GetNameOfObject(DependencyObject elem)
        {
            object tryGetName = elem.GetValue(FrameworkElement.NameProperty);

            if (tryGetName != null)
                if (!tryGetName.ToString().Equals(String.Empty))
                    _Name = tryGetName.ToString();
                else
                    _Name = "No Name";
            else
                _Name = "No Name";
        }

        /// <summary>
        /// Builds the visual tree map.
        /// </summary>
        /// <param name="elem">The element to start from.</param>
        private void BuildTree(DependencyObject elem)
        {
            GetNameOfObject(elem);

            foreach (var item in elem.GetType().GetProperties())
            {
                this.Properties.Add(new Property(item, elem));
            }

            _Type = elem.GetType().FullName.ToString();
            _HashCode = elem.GetHashCode();

            try
            {
                int numChildren = VisualTreeHelper.GetChildrenCount(elem);

                if (numChildren > 0)
                {
                    for (int i = 0; i < numChildren; i++)
                    {
                        var item = VisualTreeHelper.GetChild(elem, i);

                        if (item == null
                            || item is Inspector)
                            continue;

                        this.Children.Add(new VisualStructure(item));
                    }
                }

                if (elem is ItemsControl)
                {
                    ItemsControl parentControl = elem as ItemsControl;
                    int total = 0;
                    if (parentControl.ItemsSource != null)
                    {
                        foreach (var item in parentControl.ItemsSource)
                        {
                            total++;
                        }

                        this._TotalItems = total;
                    }
                    else
                        this._TotalItems = parentControl.Items.Count;
                }
                else
                    this._TotalItems = 0;

            }
            catch (Exception ex)
            {

            }
        }

        /// <summary>
        /// Initializes a new instance of the VisualStructure class.
        /// </summary>
        public VisualStructure(DependencyObject elem)
        {
            BuildTree(elem);
        }

        /// <summary>
        /// Holds the children of this visual element.
        /// </summary>
        private ObservableCollection<VisualStructure> _Children =
            new ObservableCollection<VisualStructure>();

        /// <summary>
        /// Gets the children of this visual element in the
        /// visual tree.
        /// </summary>
        public ObservableCollection<VisualStructure> Children
        {
            get { return _Children; }
        }

        /// <summary>
        /// Holds the local name of this element.
        /// </summary>
        private string _Name;
        
        /// <summary>
        /// Gets the name of this element in the visual tree.
        /// </summary>
        public string Name
        {
            get { return _Name; }

        }

        /// <summary>
        /// Holds the local type of this element.
        /// </summary>
        private string _Type;

        /// <summary>
        /// Gets the string representation of this type
        /// in the visual tree.
        /// </summary>
        public string Type
        {
            get { return _Type; }
        }

        /// <summary>
        /// Holds a list of properties about the wrapped object.
        /// </summary>
        private List<Property> _Properties =
            new List<Property>();

        /// <summary>
        /// Gets a list of PropertyInfo containing the properties
        /// of the wrapped object.
        /// </summary>
        public List<Property> Properties
        {
            get { return _Properties; }
        }

    }

    public class Property
    {
        private object _Value;
        public object Value
        {
            get { return _Value; }
            set
            {
                _Value = value;
            }
        }

        private string _Name;
        public string Name
        {
            get { return _Name; }
            set
            {
                _Name = value;
            }
        }

        private Type _Type;
        public Type Type
        {
            get { return _Type; }
            set
            {
                _Type = value;
            }
        }

        private object _orig;
        private System.Reflection.PropertyInfo _prop;

        /// <summary>
        /// Initializes a new instance of the Property class.
        /// </summary>
        public Property(System.Reflection.PropertyInfo property, Object orig)
        {
            this.Name = property.Name;
            this.Type = property.PropertyType;
            this.Value = property.GetValue(orig, null);

            _prop = property;
            _orig = orig;
        }
    }
}
